import type * as Koa from 'koa';
import KoaRouter from '@koa/router';
import KoaSession from 'koa-session';

import CtCasClient from './CtCasClient';
import config from '../../config';
import { ConfigApiPaths } from '../config';
import { ProxyPaths } from '../proxy';

export enum CasClientPaths {
  FetchMe = '/api/me',
  Logout = '/api/logout',
  ToValidate = '/api/casClient/toValidate',
}

export const registerCasService = (app: Koa, router: KoaRouter) => {
  app.keys = ['ctconsole-session-secret'];

  const sessionMiddleware = KoaSession({
    key: 'ctsession',
    maxAge: 1 * 60 * 60 * 1000,
    renew: true,
  }, app);
  app.use(sessionMiddleware);

  if (!config.cas.url || !config.cas.serviceUrl) {
    throw new Error('CAS client init failed, cause of cas config is not valid.');
  }

  const casSessionInfoKey = 'cas_user_detail';
  const casClient = new CtCasClient({
    serverUrl: config.cas.url,
    serviceUrl: config.cas.serviceUrl,
    sessionInfoKey: casSessionInfoKey,
  });

  const casBlockIgnorePaths = [
    ConfigApiPaths.Config,
    ProxyPaths.StandaloneBackend,
    ProxyPaths.StandalonePlatformSso,
    CasClientPaths.ToValidate,
    CasClientPaths.Logout,
  ];

  app.use(async (context, next) => {
    const shouldIgnoreCasCheck = casBlockIgnorePaths.some((ignorePath) => {
      return context.request.path.startsWith(ignorePath);
    });
    if (shouldIgnoreCasCheck) {
      await next();
    } else {
      await casClient.tryToBlock(context, next);
    }
  });

  router.get(CasClientPaths.FetchMe, (context) => {
    if (context.session && context.session[casSessionInfoKey]) {
      context.body = context.session[casSessionInfoKey];
    }
  });

  router.get(CasClientPaths.ToValidate, async (context) => {
    if (context.query.ticket) {
      await casClient.queryTicket(context);
    }
    // 在前端主动请求校验 ticket 成功后，不返回 302，而是返回 200 和 serviceUrl 链接，让前端主动前往该链接，以避免多次 302 导致的跨域问题
    // https://gitlab.ctyun.cn/zhanglm8/cloud-native-security-frontend/-/issues/3#note_100923
    if (context.status === 302) {
      context.status = 200;
      context.body = { redirectTo: config.cas.serviceUrl };
    }
  });

  router.get(CasClientPaths.Logout, casClient.logout);
};
